let canvas = $('#canvas')
let ctx = canvas.getContext('2d')

let treeConfig = {
    n: 5,
    cWidth: 600,
    cHeight: 600,

    r: 22,
    yDis: 100,
    nodes: [],
    levelArr: [],
}

class Node {
    constructor(ctx, text) {
        this.name = ''
        this.ctx = ctx
        this.x = 0
        this.y = 0
        this.r = treeConfig.r
        this.opacity = 1
        this.text = text
        this.left = null
        this.right = null
        this.parent = null
        this.deep = 0
        this.visible = true
        treeConfig.nodes.push(this)
    }

    renderLine() {
        this.ctx.strokeStyle = `rgba(0, 0, 0, ${this.opacity})`
        if (this.left && this.left.opacity) {
            this.ctx.beginPath()
            this.ctx.moveTo(this.x, this.y)
            this.ctx.lineTo(this.left.x, this.left.y)
            this.ctx.stroke()
        }
        if (this.right && this.right.opacity) {
            this.ctx.beginPath()
            this.ctx.moveTo(this.x, this.y)
            this.ctx.lineTo(this.right.x, this.right.y)
            this.ctx.stroke()
        }
    }

    render() {
        if (!this.visible) {
            return
        }
        this.renderLine()
        this.ctx.beginPath()

        this.ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, true)
        this.ctx.fillStyle = `rgba(241, 243, 244, ${this.opacity})`
        this.ctx.fill()

        this.ctx.fillStyle = `rgba(0, 0, 0, ${this.opacity})`
        this.ctx.lineWidth = 2
        this.ctx.strokeStyle = `rgba(0, 0, 0, ${this.opacity})`
        this.ctx.stroke()

        this.ctx.font = `${18}px serif`
        this.ctx.textAlign = 'center'
        this.ctx.textBaseline = 'middle'
        this.ctx.fillText(this.text, this.x, this.y)

        this.ctx.closePath()
    }
}

function makeTree(n, deep = 0, parent) {
    if ([0, 1, 2].includes(n)) {
        let root = new Node(ctx, `f(${n})`)
        root.deep = deep
        if (parent) {
            root.name = `${parent.name}-${n}`
            root.parent = parent
        } else {
            root.name = `${n}`
        }
        return root
    } else {
        let root = new Node(ctx, `f(${n})`)
        root.deep = deep
        if (parent) {
            root.name = `${parent.name}-${n}`
            root.parent = parent
        } else {
            root.name = `${n}`
        }
        root.left = makeTree(n - 1, deep + 1, root)
        root.right = makeTree(n - 2, deep + 1, root)
        return root
    }
}

function renderTree() {
    ctx.clearRect(0, 0, canvas.width, canvas.height)
    for (const i of treeConfig.nodes) {
        i.render()
    }
}

// 层次遍历，设置每一个节点x值
function level(root) {
    let res = []
    let arr = []
    arr.push(root)
    while (arr.length) {
        temp = arr.shift()
        res.push(temp)
        if (temp.left) {
            arr.push(temp.left)
        }
        if (temp.right) {
            arr.push(temp.right)
        }
    }
    // 计算x
    let deep = 0
    let index = 0
    for (const i of res) {
        if (i.deep != deep) {
            deep = i.deep
            index = 0
        }
        if (i.parent) {
            let offset = treeConfig.cWidth / 2 ** deep

            if (i.parent.left) {
                i.parent.left.x = i.parent.x - offset / 2
            }
            if (i.parent.right) {
                i.parent.right.x = i.parent.x + offset / 2
            }
        }
        i.y = deep * treeConfig.yDis + treeConfig.r + 10
        index++
    }
    return res
}

function initTree() {
    if (treeConfig.n > 5 && canvas.parentElement.className == 'min-tree') {
        // 移动到max-tree里
        $('.max-tree').appendChild($('.tree-title'))
        $('.max-tree').appendChild(canvas)
    } else if (
        treeConfig.n <= 5 &&
        canvas.parentElement.className == 'max-tree'
    ) {
        $('.min-tree').appendChild($('.tree-title'))
        $('.min-tree').appendChild(canvas)
    }

    treeConfig.nodes = []
    let root = makeTree(treeConfig.n, 0)
    // 设置canvas宽度
    treeConfig.cWidth =
        2 ** (treeConfig.n - 1) * treeConfig.r + 2 ** (treeConfig.n - 1) * 10
    // 设置纵向距离
    treeConfig.yDis = treeConfig.n * 20
    treeConfig.cHeight = treeConfig.yDis * (treeConfig.n - 1)

    canvas.width = treeConfig.cWidth
    canvas.height = treeConfig.cHeight
    root.x = treeConfig.cWidth / 2
    treeConfig.levelArr = level(root)
    renderTree()
}

let treeAction = {
    setText(name, text) {
        treeConfig.nodes.findIndex((v) => {
            if (v.name === name) {
                v.text = text
                return true
            } else {
                return false
            }
        })
        renderTree()
    },
    showNode(name) {
        treeConfig.nodes.findIndex((v) => {
            if (v.name === name) {
                v.opacity = 1
                return true
            } else {
                return false
            }
        })
        renderTree()
    },
}

// initTree()
